#include <list>

#include "Operation.h"
#include "Rules.h"
#include "RuleCompiler.h"

/*
 * ProxyRule
 */

void ProxyRule::set(AbstractRule *src)
{
	rule = src;
}

AbstractRule *ProxyRule::get(void)
{
	return rule;
}

void ProxyRule::compile(RuleCompiler &compiler, const Operation &oper)
{
	compiler.compile(*this, oper);
}

ProxyRule::~ProxyRule()
{
	delete rule;
}

/*
 * RootRule
 */

bool RootRule::check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const
{
	return rule->check(prevIp, curIp, prevTcp, curTcp);
}

AbstractRule *RootRule::clone(void) const
{
	return new RootRule(*this);
}

/*
 * ComplexRule
 */

void ComplexRule::push_back(AbstractRule *rule)
{
	rules.push_back(rule);
}

AbstractRule *ComplexRule::back(void)
{
	return rules.back();
}

void ComplexRule::compile(RuleCompiler &compiler, const Operation &oper)
{
	compiler.compile(*this, oper);
}

ComplexRule::~ComplexRule()
{
	std::list<AbstractRule *>::const_iterator i;
	for (i = rules.begin(); i != rules.end(); ++i)
		delete *i;
}

/*
 * ComplexANDRule
 */

bool ComplexANDRule::check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const
{
	std::list<AbstractRule *>::const_iterator i;
	for (i = rules.begin(); i != rules.end(); ++i) {
		if (!(*i)->check(prevIp, curIp, prevTcp, curTcp))
			return false;
	}
	return true;
}

AbstractRule *ComplexANDRule::clone(void) const
{
	return new ComplexANDRule(*this);
}

/*
 * ComplexORRule
 */

bool ComplexORRule::check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const
{
	std::list<AbstractRule *>::const_iterator i;
	for (i = rules.begin(); i != rules.end(); ++i) {
		if ((*i)->check(prevIp, curIp, prevTcp, curTcp))
			return true;
	}
	return false;
}

AbstractRule *ComplexORRule::clone(void) const
{
	return new ComplexORRule(*this);
}

/*
 * NOTRule
 */

bool NOTRule::check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const
{
	return !rule->check(prevIp, curIp, prevTcp, curTcp);
}

AbstractRule *NOTRule::clone(void) const
{
	return new NOTRule(*this);
}

/*
 * EqualsRule
 */

bool EqualsRule::check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const
{
	unsigned long data = getWord(curIp, curTcp, offset);
	data &= mask;
#ifdef DEBUG
	std::cout << std::hex << "Data: " << data << ", Value: " << value << std::dec << std::endl;
#endif
	return !(data ^ value);
}

AbstractRule *EqualsRule::clone(void) const
{
	return new EqualsRule(*this);
}

void EqualsRule::compile(RuleCompiler &compiler, const Operation &oper)
{
	compiler.compile(*this, oper);
}

/*
 * DifferRule
 */

bool DifferRule::check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const
{
	if (!prevIp || !prevTcp)
		return false;

	unsigned long val = getWord(curIp, curTcp, offset);
	unsigned long old = getWord(prevIp, prevTcp, offset);
	unsigned long tmp, tmp2;

	old &= mask;
	val &= mask;
#ifdef DEBUG
	std::cout << std::hex << "Old: " << old << ", New: " << val << std::dec << std::endl;
#endif
	tmp = val;
	tmp += delta;
	if (tmp < val)
		tmp |= mask;
	tmp2 = tmp - old;
	if (tmp2 > tmp)
		return true;

	tmp = old;
	tmp += delta;
	if (tmp < old)
		tmp |= mask;
	tmp2 = tmp - val;
	if (tmp2 > tmp)
		return true;

	return false;
}

AbstractRule *DifferRule::clone(void) const
{
	return new DifferRule(*this);
}

void DifferRule::compile(RuleCompiler &compiler, const Operation &oper)
{
	compiler.compile(*this, oper);
}
